/*
* 初始化立方体数据，由两个三角形条带组成
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../common/LoadShaders.h"
#include "../include/vmath.h"

#define BUFFER_OFFSET(offset) ((void*) (offset))

const unsigned int SCR_WIDTH = 512;
const unsigned int SCR_HEIGHT = 512;

void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
    {
        //将窗口设置为关闭，跳出循环
        glfwSetWindowShouldClose(window, 1);
    }
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, NumBuffers };
enum Attrib_IDs { vPosition = 0, vColor=1 };

//GLuint VAOs[NumVAOs];
//GLuint Buffers[NumBuffers];

GLuint ebo[1];
GLuint vao[1];
GLuint vbo[1];

const GLuint NumVertices = 6;
GLint render_model_matrix_loc;
GLint render_projection_matrix_loc;
float aspect = 1.0;

const GLfloat positions[] = {
     1.0f,  1.0f, -1.0f, 1.0f,
     1.0f, -1.0f, -1.0f, 1.0f,
    -1.0f,  1.0f, -1.0f, 1.0f,
    -1.0f, -1.0f, -1.0f, 1.0f,

    -1.0f,  1.0f,  1.0f, 1.0f,
    -1.0f, -1.0f,  1.0f, 1.0f,
     1.0f,  1.0f,  1.0f, 1.0f,
     1.0f, -1.0f,  1.0f, 1.0f,
};

const GLfloat colors[] = {
    1.0f, 1.0f, 1.0f, 1.0f,
    1.0f, 1.0f, 0.0f, 1.0f,
    1.0f, 0.0f, 1.0f, 1.0f,
    1.0f, 0.0f, 0.0f, 1.0f,

    0.0f, 1.0f, 1.0f, 1.0f,
    0.0f, 1.0f, 0.0f, 1.0f,
    0.0f, 0.0f, 1.0f, 1.0f,
    0.5f, 0.5f, 0.5f, 1.0f,
};

const GLushort indices[] = {
  0, 1, 2, 3, 4, 5, 6, 7,
  0xFFFF,
  4, 2, 6, 0, 7, 1, 5, 3
};

void init(void)
{
    glClearColor(0, 0, 0, 1);
    glFrontFace(GL_CCW);

    ShaderInfo shaders[] = {
        { GL_VERTEX_SHADER, "triangles.vert" },
        { GL_FRAGMENT_SHADER, "triangles.frag" },
        { GL_NONE, NULL }
    };

    GLuint program = LoadShaders(shaders);
    glUseProgram(program);

    render_model_matrix_loc = glGetUniformLocation(program, "model_matrix");
    render_projection_matrix_loc = glGetUniformLocation(program, "projection_matrix");

    // set ebo
    glGenBuffers(1, ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[0]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                 sizeof(indices),
                 indices,
                 GL_STATIC_DRAW);

    // set vertex property
    glGenVertexArrays(1, vao);
    glBindVertexArray(vao[0]);

    glGenBuffers(1, vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glBufferData(GL_ARRAY_BUFFER,
                 sizeof(positions)+sizeof(colors),
                 NULL,
                 GL_STATIC_DRAW);
    glBufferSubData(GL_ARRAY_BUFFER, 0,
                    sizeof(positions),
                    positions);
    glBufferSubData(GL_ARRAY_BUFFER,
                    sizeof(positions),
                    sizeof(colors),
                    colors);

    glVertexAttribPointer(0, 4, GL_FLOAT,
                          GL_FALSE,
                          4*sizeof(GLfloat),
                          BUFFER_OFFSET(0));
    glVertexAttribPointer(1, 4, GL_FLOAT,
                          GL_FALSE,
                          4*sizeof(GLfloat),
                          BUFFER_OFFSET(sizeof(positions)));


    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
}
//#define USE_PRIMITIVE_RESTART 1
void display(void)
{
    vmath::mat4 model_matrix;

//    glEnable(GL_CULL_FACE);
//    glEnable(GL_DEPTH_TEST);

    glClear(GL_COLOR_BUFFER_BIT);

    //设置投影矩阵，只需执行一次
    vmath::mat4 projection_matrix(vmath::frustum(-1.0f, 1.0f, -aspect, aspect, 1.0f, 500.0f));
    glUniformMatrix4fv(render_projection_matrix_loc,
                       1,
                       GL_FALSE,
                       projection_matrix);


    glBindVertexArray(vao[0]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[0]);

#if USE_PRIMITIVE_RESTART
//    std::cout << "USE_PRIMITIVE_RESTART" << std::endl;
    glEnable(GL_PRIMITIVE_RESTART);
    glPrimitiveRestartIndex(0xFFFF);

    model_matrix = vmath::translate(-2.0f, 0.0f, -5.0f);
    glUniformMatrix4fv(render_model_matrix_loc,
                       1,
                       GL_FALSE,
                       model_matrix);
    glDrawElements(GL_TRIANGLE_STRIP, 17, GL_UNSIGNED_SHORT, NULL);
#else
    model_matrix = vmath::translate(-2.0f, 0.0f, -5.0f);
    glUniformMatrix4fv(render_model_matrix_loc,
                       1,
                       GL_FALSE,
                       model_matrix);

    //因为glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[0]);所以 indices=NULL
    glDrawElements(GL_TRIANGLE_STRIP, 8, GL_UNSIGNED_SHORT, NULL);

    model_matrix = vmath::translate(2.0f, 0.0f, -5.0f);
    glUniformMatrix4fv(render_model_matrix_loc,
                       1,
                       GL_FALSE,
                       model_matrix);
    glDrawElements(GL_TRIANGLE_STRIP, 8, GL_UNSIGNED_SHORT,
                   BUFFER_OFFSET(9*sizeof(GLushort)));


#endif
    glFlush();
}


int main()
{
    //glfw初始化
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    //glfw创建窗口
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "OpenGL编程指南", NULL, NULL);

    if (window == NULL)
    {
        printf("创建窗口失败");
        //终止
        glfwTerminate();
        return -1;
    }

    //显示窗口
    glfwMakeContextCurrent(window);

    //设置回调，当窗口大小调整后将调用该回调函数
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // glad初始化
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        printf("加载失败");
        return -1;
    }

    init();

    // 使用循环达到循环渲染效果
    while (!glfwWindowShouldClose(window))
    {
        display();
        //自定义输入事件
        processInput(window);
        //交互缓冲区，否则显示空白
        glfwSwapBuffers(window);
        //输入输出事件,否则无法对窗口进行交互
        glfwPollEvents();
    }

    //终止渲染 关闭并清理glfw本地资源
    glfwTerminate();
    return 0;
}
